using System;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using NotifyCenter.EntityFrameworkCore;
using NotifyCenter.MediatR.Etos;
using NotifyCenter.NotificationRecords;
using NotifyCenter.Projects;

namespace NotifyCenter.MediatR.Handlers;

public class MessageSendingStatusChangedHandler(
    NotifyCenterDbContext dbContext,
    ILogger<MessageSendingStatusChangedHandler> logger,
    IPublisher publisher) : INotificationHandler<MessageSendingStatusChangedEto>
{
    public async Task Handle(MessageSendingStatusChangedEto eto, CancellationToken cancellationToken)
    {
        logger.LogInformation("Record {RecordId} status: {Status}. Message: {Message}", eto.RecordId, eto.Type, eto.Message);

        var record = await dbContext.Set<NotificationRecord>()
            .AsNoTracking()
            .FirstOrDefaultAsync(r => r.Id == eto.RecordId, cancellationToken);

        if (record is null)
        {
            logger.LogWarning("Skip webhook dispatch: record {RecordId} was not found.", eto.RecordId);
            return;
        }

        var notification = await dbContext.Set<NotificationRule>()
            .AsNoTracking()
            .FirstOrDefaultAsync(rule => rule.Id == record.NotificationRuleId, cancellationToken);

        if (notification is null)
        {
            logger.LogWarning("Skip webhook dispatch: notification rule {RuleId} was not found.", record.NotificationRuleId);
            return;
        }

        if (!notification.EnableWebhook || string.IsNullOrWhiteSpace(notification.WebhookUrl))
        {
            logger.LogDebug("Webhook disabled for notification rule {RuleId}.", notification.Id);
            return;
        }

        if (!Uri.TryCreate(notification.WebhookUrl, UriKind.Absolute, out var callbackUri))
        {
            logger.LogWarning("Webhook url {Url} is invalid.", notification.WebhookUrl);
            return;
        }

        var webhookEto = new NotificationWebhookEto
        {
            Callback = callbackUri,
            Secret = string.IsNullOrWhiteSpace(notification.WebhookSecret) ? null : notification.WebhookSecret,
            ProjectId = record.ProjectId,
            NotificationRuleId = notification.Id,
            RecordId = record.Id,
            NotificationName = notification.Name,
            NotificationType = notification.Type,
            Status = eto.Type,
            StatusMessage = eto.Message,
            OccurredAtUtc = DateTimeOffset.UtcNow
        };

        try
        {
            await publisher.Publish(webhookEto, cancellationToken);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Webhook publish failed for record {RecordId}", eto.RecordId);
        }
    }
}
